package eval.gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.jfree.data.xy.XYIntervalSeries;
import se.diod.swing.JxPanel;
import eval.results.IResultsData;
import eval.utilities.configuration.ExperimentConfiguration;

/**
 * Create The GUI for the result
 * 
 * @author Nicolo' M. Calcavecchia <calcavecchia@elet.polimi.it>
 * @author Amit Peled   <amit.kapina@gmail.com>
 * @author Igal Kaufman <igal.kaufman@gmail.com>
 */
public class ResultsFrame extends JFrame {

	private static final long serialVersionUID = 1L;
	private List<IResultsData> resultsList;
	private GridBagConstraints cJx;
	private GridBagConstraints c;
	private JPanel panel;
	private String resFileName;

	/**
	 * @Constructor
	 * @param resultsData
	 * @param resFileName
	 */
	public ResultsFrame(List<IResultsData> resultsData, String resFileName) {
		super("Placements results");
		this.resultsList = resultsData;
		this.resFileName = resFileName;
		init();
	}

	private void init() {
		this.panel = new JPanel();
		panel.setLayout(new GridBagLayout());

		this.cJx = new GridBagConstraints();
		cJx.fill = GridBagConstraints.BOTH;
		cJx.weightx = 1.0;
		cJx.weighty = 1.0;
		cJx.gridx = 0;
		cJx.gridy = 0;

		this.c = new GridBagConstraints();
		c.weightx = 1.0;
		c.weighty = 1.0;
		c.gridx = 0;
		c.gridy = 0;

		//Create the components for the GUI
		createPlotPanel("VM Rejected", createRejected("vmRejected") );
		createPlotPanel("VM Relocated ", createVmRelocated("vmRelocated") );
		createPlotPanel("Total Cpu Free At Open Hosts", createTotalCpuFreeAtCloud("CpuFree"));
		createPlotPanel("Sum of Min of VM / Total capcity", createMinOnTotalDemand("minOnCap"));
		createPlotPanel("Total Requested Demand / Total capcity", createTotalDemand("demand") );
		createPlotPanel("Gradient values", createGradientValues("Gradient"));
		createPlotPanel("Satisfied  Demand (CPU) ", createSatisfiedDemand("satisfiedDemand"));
		createPlotPanel("Un-Satisfied Demand (CPU)", createUnSatisfiedDemand("unSatisfiedDemand"));
		createPlotPanel("Energy (Cost)", createTotalConsumption("energy"));
		createPlotPanel("total income balance", createTotalBalance("balance"));
		createPlotPanel("Open Host", createNumberOfOpenHost("openHost"));
		createFreeCpuAtHost("freeCpuAtHost");

		add(new JScrollPane(panel));

		setPreferredSize(new Dimension(800, 800));

		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
	}

	private void createFreeCpuAtHost(String chartLabel) {
		for(int l=0;l<ExperimentConfiguration.getSingleton().totalNumberOfHosts;l++){
			String tag;
			int cap = 0;
			List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
			for(int i=0; i<resultsList.size();i++) {
				IResultsData results = resultsList.get(i);
				tag = results.getEngineType();
				final XYIntervalSeries totalDemandSeries = new XYIntervalSeries(tag);
				double[] t = results.ggetFreeCpuAtOpenHosts(l);
				if(cap ==0) {
					cap = results.ggetHostCap(l);
				}
				for (int j = 0; j < results.getExperimentTicks(); j++) {
					double v = t[j];
					totalDemandSeries.add(j, j, j, v, v, v);
				}
				seriesList.add(totalDemandSeries);
			}
			Component plot = new PlotPanel("Tick", "free Cpu", true, seriesList, 0,chartLabel+"-"+(l+1),resFileName);
			createPlotPanel("host-"+(l+1)+" capacity: "+cap,plot);
		}
	}

	private Component createTotalDemand(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries totalDemandSeries = new XYIntervalSeries(tag);
			double[] totalDemand = results.getTotalCpuDemandAtCloud();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				double v = totalDemand[j];
				totalDemandSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(totalDemandSeries);
		}
		Component plot = new PlotPanel("Tick", "GHz", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}

	private Component createMinOnTotalDemand(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries minOnTotalDemandSeries = new XYIntervalSeries(tag);
			double[] minOnTotalDemand = results.getSumOfMinREservtion();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				double v = minOnTotalDemand[j];
				minOnTotalDemandSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(minOnTotalDemandSeries);
		}
		Component plot = new PlotPanel("Tick", "GHz", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}

	private Component createNumberOfOpenHost(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries incomeForDemandSeries = new XYIntervalSeries(tag);
			int[] incomeforDemand = results.getNumberOfOpenHostAtCloud();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				int v = incomeforDemand[j];
				incomeForDemandSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(incomeForDemandSeries);
		}
		Component plot = new PlotPanel("Tick", "Hosts", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}

	private Component createGradientValues(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries GradientValueSeries = new XYIntervalSeries(tag);
			int[] GradientValue = results.getGradientValue();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				int v = GradientValue[j];
				GradientValueSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(GradientValueSeries);
		}
		Component plot = new PlotPanel("Tick", "Angle", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}




	private Component createSatisfiedDemand(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries satisfiedDemandSeries = new XYIntervalSeries(tag);
			int[] SatisfiedDemand = results.getTotalDemandSatisfiedAtCloud();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				int v = SatisfiedDemand[j];
				satisfiedDemandSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(satisfiedDemandSeries);
		}
		Component plot = new PlotPanel("Tick", "GHz", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}

	private Component createUnSatisfiedDemand(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries unSatisfiedDemandSeries = new XYIntervalSeries(tag);
			int[] unSatisfiedDemand = results.getTotalDemandUnSatisfiedAtCloud();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				int v = unSatisfiedDemand[j];
				unSatisfiedDemandSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(unSatisfiedDemandSeries);
		}
		Component plot = new PlotPanel("Tick", "GHz", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}

	private Component createTotalConsumption(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries totalConsumptionSeries = new XYIntervalSeries(tag);
			double[] totalConsumption = results.getTotalConsumption();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				double v = totalConsumption[j];
				totalConsumptionSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(totalConsumptionSeries);
		}
		Component plot = new PlotPanel("Tick", "Electricity", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}

	private Component createTotalBalance(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries totalBalanceSeries = new XYIntervalSeries(tag);
			double[] totalBalance = results.getBalanceOfIncome();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				double v = totalBalance[j];
				totalBalanceSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(totalBalanceSeries);
		}
		Component plot = new PlotPanel("Tick", "$", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}



	private Component createRejected(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries rejectedSeries = new XYIntervalSeries(tag);
			int[] rejected = results.getNumberOfVmsReject();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				int v = rejected[j];
				rejectedSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(rejectedSeries);
		}
		Component plot = new PlotPanel("Tick", "VM's", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}

	private Component createVmRelocated(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries vmRelocatedSeries = new XYIntervalSeries(tag);
			int[] vmRelocated = results.getvmRelocate();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				int v = vmRelocated[j];
				vmRelocatedSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(vmRelocatedSeries);
		}
		Component plot = new PlotPanel("Tick", "VM's", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}

	private Component createTotalCpuFreeAtCloud(String chartLabel) {
		String tag;
		List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
		for(int i=0; i<resultsList.size();i++) {
			IResultsData results = resultsList.get(i);
			tag = results.getEngineType();
			final XYIntervalSeries totalCpuFreeAtCloudSeries = new XYIntervalSeries(tag);
			double[] totalCpuFreeAtCloud = results.getTotalCpuFreeAtCloud();
			for (int j = 0; j < results.getExperimentTicks(); j++) {
				double v = totalCpuFreeAtCloud[j];
				totalCpuFreeAtCloudSeries.add(j, j, j, v, v, v);
			}
			seriesList.add(totalCpuFreeAtCloudSeries);
		}
		Component plot = new PlotPanel("Tick", "GHz", true, seriesList, 0,chartLabel,resFileName);
		return plot;
	}

	private void createPlotPanel(String title, Component component) {
		JxPanel plotPanel = createJxPanel(title);
		plotPanel.setLayout(new GridBagLayout());
		plotPanel.add(component, cJx);
		panel.add(plotPanel, c);
		// increment grid row
		c.gridy++;
	}

	public void display() {
		pack();
		setLocationRelativeTo(null);
		setVisible(true);
	}

	private final static GradientPaint JX_PANEL_GRADIENT = new GradientPaint(0,
			0, new Color(255, 168, 21), 500, 0, Color.white);
	private final static Color JX_PANEL_FONT_COLOR = new Color(200, 1, 1);

	private static JxPanel createJxPanel(String title) {
		JxPanel jxPanel = new JxPanel(title);
		jxPanel.setCollapsable(true);
		jxPanel.setGradient(JX_PANEL_GRADIENT);
		jxPanel.setFontColor(JX_PANEL_FONT_COLOR);
		return jxPanel;
	}
}
